其他
如何实现限制用户 1 分钟内最多请求 1000 次?
在高并发场景下,如何保护你的服务不被海量请求压垮?限流器是你的不二之选。本文将带你使用 Go 语言,实现一个高效的限流器,限制每分钟内用户的最大请求次数。
限流算法的选择
常见的限流算法有很多,例如:
计数器算法: 设定一个时间窗口,在窗口内对请求进行计数,超过阈值则拒绝请求。 漏桶算法: 将请求想象成水滴,漏桶以固定速率漏水,溢出则拒绝请求。 令牌桶算法: 以固定速率生成令牌放入桶中,请求需要获取令牌才能通过,桶满则丢弃令牌。
本文将采用计数器算法,因为它实现简单且性能较高,非常适合限制固定时间窗口内的请求次数。
Go 代码实现
package main
import (
"fmt"
"sync"
"time"
)
// Limiter 定义限流器结构体
type Limiter struct {
rate int // 每分钟请求限制
unit time.Duration // 时间单位
mutex sync.Mutex // 并发控制锁
count int // 当前时间窗口内的请求计数
reset time.Time // 时间窗口重置时间
}
// NewLimiter 创建一个新的限流器
func NewLimiter(rate int, unit time.Duration) *Limiter {
return &Limiter{
rate: rate,
unit: unit,
mutex: sync.Mutex{},
count: 0,
reset: time.Now(),
}
}
// Allow 判断是否允许请求通过
func (l *Limiter) Allow() bool {
l.mutex.Lock()
defer l.mutex.Unlock()
// 检查是否需要重置时间窗口
if time.Since(l.reset) >= l.unit {
l.count = 0
l.reset = time.Now()
}
// 判断请求是否超过限制
if l.count >= l.rate {
return false
}
// 请求计数加一
l.count++
return true
}
func main() {
// 创建一个每分钟限制1000次请求的限流器
limiter := NewLimiter(1000, time.Minute)
// 模拟用户请求
for i := 0; i < 1500; i++ {
if limiter.Allow() {
fmt.Println("请求", i+1, "通过")
} else {
fmt.Println("请求", i+1, "被限流")
}
time.Sleep(time.Millisecond * 10) // 模拟请求间隔
}
}
代码解析
Limiter 结构体: 存储限流器相关信息,包括每分钟请求限制、时间单位、并发控制锁、当前请求计数和时间窗口重置时间。 NewLimiter 函数: 创建一个新的限流器实例,并初始化相关参数。 Allow 函数: 判断是否允许请求通过。首先获取锁,确保并发安全。然后检查是否需要重置时间窗口,如果需要则重置计数和时间。接着判断请求是否超过限制,超过则返回 false,否则计数加一并返回 true。 main 函数: 创建一个限流器实例,并模拟用户请求。
总结
本文介绍了使用 Go 语言实现一个简单的限流器的过程,并详细解释了代码逻辑。你可以根据实际需求,调整限流参数或选择更复杂的限流算法。合理使用限流器,可以有效保护你的服务免受流量冲击,提高服务的稳定性和可靠性。
其它两种算法的具体实现可以在公众号内回复 ”限流算法“ 进行查看。